///<reference path="Util.js"/>
///<reference path="MSArray.js"/>

MNovaUtil2 = function(selector)
{
/// <summary>1: Update the window
/// 1.1 - MNovaUtil()
/// 2: Find the item or items based on the selector string.
/// 2.1 - MNovaUtil("S")
/// 2.2 - MNovaUtil("S 1")
/// 2.3 - MNovaUtil("S PT")</summary>
///<param name="selector" type="String">String to find an item in the MNova app</param>
///<returns type="MNovaUtil">the found object</returns>

//more types: Function Date Int Object Boolean
//example: <param name="callback" type="Function">The function that will be executed on every object.</param>
	// <returns type="Number" />
	// <param name="elem" type="Object">The value to search for.</param>
	// <param name="array" type="Array">An array through which to search.</param>

	 this.version = "0.0.6";
	 this.excepts = 4657;
		this.checkVersion(this.excepts);

		this.init();


	  if ( !selector )
			return this;


	 // Handle searching with $.find(...)
	 if ( typeof selector === "string" ) {
		return this.find(selector);
	 }
}


MNovaUtil2.prototype = {


	init : function () {
	this.fn = this.prototype;
	this.mainWindow = mainWindow;

	if (typeof mainWindow.activeDocument !='undefined'){
		this.window = mainWindow.activeDocument;

		this.uuid = this.window.uuid;
		if (this.window.pageCount()>0){
		this.page = new Page(this.window.curPage());
		this.pageOffest = {};
		this.pageOffest.top = this.page.top;
		this.pageOffest.left = this.page.left;
		this.pageOffest.right = this.page.right;
		this.pageOffest.width = this.pageOffest.right - this.pageOffest.left;
		this.pageOffest.bottom = this.page.bottom;
		this.pageOffest.height = this.pageOffest.bottom - this.pageOffest.top;
		}
	}
	this.defaultDialogs();

	},

	checkFunction: function(functionName){
	 if ((typeof mainWindow.activeDocument =='undefined')|| (mainWindow.activeDocument.pageCount==0))
		 throw 'Must have a document open to use function ' + functionName;
	},


//-------------------------------------------------GUI Calls----------------------------------------------------------

clicked : function (source, target, callback) {
//MNovaUtil.clicked(controlItem, "TextBox1", onOpenFile)
	try{
	  this.dialog.widgets[source].clicked.connect(this.dialog.widgets[target],callback);
	}
	catch (err){
	  print("failed to connect source and target for click event");
	}
},


openFileClick : function (source, target) {
//MNovaUtil.openFileClick("source", "target")
	try{
	  this.dialog.widgets[source].clicked.connect(this.dialog.widgets[target],onOpenFile);
	}
	catch (err){
	  print("failed to connect source and target for click event");
	}
},


onOpenFile : function () {
//Example callback used by MNovaUtil.openFile("s","t")
	var fileName = this.text;
	fileName = FileDialog.getSaveFileName(this.filter ? this.filter : "", "Save File", fileName.length ? File.absDirPath(fileName) : Dir.home());
	if (fileName.length){
	this.text = fileName;
	}
},



//-------------------------------------------------NMR & Mass Calls----------------------------------------------------------



checkVersion : function(version)
{
/// <summary>Checks if you can run the feature</summary>
///<param name="version" type="String">The release version of MNova that is required for this feature</param>

	 if (Application.version.revision < version && Application.version.revision !== 0)
	 {
	  MessageBox.critical("Your version of MNova doesn't support all the functionality of the script. Upgrade to the latest version of MNova.");
	  throw "Expected version {0}.  You have version {1}.".format(version,Application.version.revision);
	 }
},

isValidNMR : function(spec){
	  if(spec !== null){

		if(spec.isValid()){ return;}
	  }
	  MessageBox.critical("Not a spectrum", MessageBox.Ok);
	  throw 'Not a valid spectrum';
},

massSpectrum : function(item)
{
/// <summary>1: Read the current spectrum and validate it
/// 1.1 - MNovaUtil.massSpectrum()
/// 2: Read the current spectrum and validate it
/// 2.1 - MNovaUtil.massSpectrum(spectrumItem)</summary>
///<param name="item" type="pageItem">A page item that is a Mass Spectrum</param>
///<returns type="MassSpectrum">the found spectrum object</returns>

	  this.spec = new MassItem(item); //ODO item.rtti() -> type NMR or other...

	  if(this.spec.MassItemInfo.valid===false)
	  {
		MessageBox.critical("Not a spectrum", MessageBox.Ok);
		throw 'Not a valid spectrum';
	  }
	  return this.spec;
},

getParam : function (spec, name) {
/// <summary>1: Read the spectrum parameter
/// 1.1 - MNovaUtil.getParam("Spectrometer Frequency")</summary>
///<param name="name" type="String">Name of spectrum parameter</param>
///<returns type="String">spectrum parameter value</returns>
	return spec.getParam(name);
},

AnnotatePeak : function (spec) {
/// <summary>1: Read the spectrum parameter
/// 1.1 - MNovaUtil.getParam("Spectrometer Frequency")</summary>
///<param name="name" type="String">Name of spectrum parameter</param>
///<returns type="String">spectrum parameter value</returns>

	  this.checkFunction("AnnotatePeak");
	  var peakList = new Peaks(spec.peaks());
	  print(peakList.count);
	  for (var i = 0; i< peakList; i++){
		var peak = new Peak(peakList.at(i));
		print(peak);

		var transCoords = spec.scaleToPage({x:peak.delta(), y:peak.intensity });
		if( transCoords === undefined ) {continue;}

		var arrowEndCoords = {x: transCoords.x-10, y: transCoords.y-10};

		this.arrow({top: transCoords.y, left: transCoords.x, height: -10, width:-10});

		var txt = "Peak (delta: %1, intensity: %2)".format(peak.delta(),peak.intensity);
		var textItem = this.text(txt, {top: transCoords.y, left: transCoords.x});
		this.movePosition(textItem, {top: -textItem.height,  left: -textItem.width/2.0});
	  }
	  spec.update();
	  mainWindow.activeDocument.update();
},


template : function(templateFile){
//$.template("C:/DEMO.mnova");
	  // Check that appropriate layout template document exists.
	  var layoutTemplateDocumentName = templateFile;//"C:/DEMO.mnova";
	  if (!File.exists(layoutTemplateDocumentName)){
	return;
	  }

	  // Apply layout template
	  var tempDw = new DocumentWindow(mainWindow.activeWindow());
	  var oldTemplateHistory = tempDw.templateHistory;
	  tempDw.templateHistory = false;
	  tempDw.applyTemplateDocument(layoutTemplateDocumentName);
	  tempDw.templateHistory = oldTemplateHistory;
},
performProcess: function(processFile){
	try{
		nmr.process(processFile);
		var spec = this.find('S');  		//new NMRSpectrum( nmr.activeSpectrum());
		var proc = new NMRProcessing(spec.proc);

		//Apply the processing parameters
		spec.proc = proc;
		spec.process();
	}catch (err) {}
},
performProcessOnFile: function(specFile, processFile, callback){
	this.fileOpen(specFile);
	this.performProcess(processFile);
	if (this.isFunction(callback)) {
		callback.call(this); //perform calculation
	}
	this.fileClose(specFile);
},

items : function()
{
/// <summary>1: Read items into an array item(i) -> item[i]
/// 1.1 - MNovaUtil.items()</summary>
///<returns type="Array">Array of items</returns>
	   this.checkFunction("items");
	   var count = this.page.itemCount();
	   var i = 0;
	   var itemArray = new Array(count);
	   for(i=0; i<count; i++)
	   {
			   itemArray[i] = this.page.item(i);
	   }
	   return itemArray;
},

go: function(item){  //return page number where item found
		this.checkFunction("go");
		var uuid = item.uuid;
		mainWindow.activeDocument.pages().forEach(function(p){
			if(p.uuid == uuid) {
				mainWindow.activeDocument.setCurPage(p);
				return;
			}
			for( var i = 0;i < p.itemCount(); i++){
				if(p.item(i).uuid == uuid) {  //check all the items
					mainWindow.activeDocument.setCurPage(p);
					return;
				}
			}
		});
},

action: function(action){  //return page number where item found
		mainWindow.doAction(action);
},


buildParamTable : function(spec, parameters){
//parameters= [['Spec. no.','Comment'],['Exp. no.','EXPNO'],,['Title','Title'],,['Solvent','Solvent'],['Pulse Sequence','Pulse Sequence'],['Nucleus','Nucleus']]
/// <summary>1: Creates a table of parameters for output onto the page
/// 1.1 - MNovaUtil.buildParamTable(spectrum, Json)
/// Json is Array or Array [[],[], , []] . NOTE: blanks and strings are allowed instead of inner []...these are output as seperators </summary>
///<param name="spec" type="NMRSpectrum">NMR Spectrum</param>
///<param name="parameters" type="Json">[['Title': 'Param Name'],['Title': 'Param Name'],['Title': 'Param Name']]</param>
///<returns type="string">the string to output in HTML format</returns>

	var params = '<font face="arial", size="2">';

	for (var i=0; i< parameters.length ;i++){
	if(typeof parameters[i] == 'undefined'){
		params += "<br/>";
	}
	else if(parameters[i].length == 2){
		params += "<b>{0}: </b>{1}<br/>".format(parameters[i][0],spec.getParam(parameters[i][1]));
	}
	else{
		params += "{0}<br/>".format(parameters[i]);
	}

	}
	params += "</font>";
	return params;
},


//-----------------------------------------Dialog Extensions ----------------------------------------


show : function(DialogName,beforeCallback,afterCallback)
{
//this.show('Settings',
//            function(x){ /*set values & create signals+slots (widget event handlers)*/},
//            function(x){ /*validate user input*/}}
/// <summary>1: Creates a UI based on MNovaUtil.dialogs['DialogName'] array
/// 1.1 - if (MNovaUtil.show("DialogName")) {print("pressed OK")}
///2: Allows adding of event handlers to listen to UI widget events like clicked
///2.1 - if (MNovaUtil.showWithEvents("DialogName", function(dia){dia.connect(dia, "TextBox1", callback)})) {print("pressed OK")}
///<param name="DialogName" type="String">The name of the dialog which is in the associative array. Example for PopUp: MNovaUtil.dialogs['PopUp']</param>
///<param name="callback" type="Function">callback to add JS event handlers to capture user interaction while UI is dispalyed</param>
///<returns type="Boolean">Press Acceptted button -> True. Press Reject button -> False</returns>

	return this.showString(this.dialogs[DialogName],beforeCallback,afterCallback);
},

showAuto : function(DialogName,cacheOn,beforeCallback,afterCallback,modal)
{
/// <summary>1: Creates a UI based on MNovaUtil.dialogs['DialogName'] array
/// 1.1 - if (MNovaUtil.show("DialogName")) {print("pressed OK")}
///2: Allows adding of event handlers to listen to UI widget events like clicked
///2.1 - if (MNovaUtil.showWithEvents("DialogName", function(dia){dia.connect(dia, "TextBox1", callback)})) {print("pressed OK")}
///<param name="DialogName" type="String">The name of the dialog which is in the associative array. Example for PopUp: MNovaUtil.dialogs['PopUp']</param>
///<param name="callback" type="Function">callback to add JS event handlers to capture user interaction while UI is dispalyed</param>
///<returns type="Boolean">Press Acceptted button -> True. Press Reject button -> False</returns>

	this.dailog = Application.loadUi(this.dialogs[DialogName]);

	events = [];
	if(typeof modal == 'undefined') modal =true;
	if(typeof cacheOn == 'undefined') cacheOn =true;

	for( var w in this.dailog.widgets){
			try{
			w = this.widget(w);
			if(w.text == '...' && w.styleSheet.length > 0){
						var target = w.styleSheet.split(',')[1]; //this.pickSaveFile('resultSaveFileText')
						var cmd = w.styleSheet.split(',')[0];
						if(w.styleSheet.split(',').length >= 3){
							//We have a 3rd item ...typically a filter like: //Text Files (*.txt)|CSV Files (*.csv)
							var filter = w.styleSheet.split(',')[2];
							events[w.objectName] = "sup.widget('{0}').text = sup.{1}('{2}','{3}');".format(target,cmd,target,filter);
						}
						else{
								//No extra params
								events[w.objectName] = "sup.widget('{0}').text = sup.{1}('{2}');".format(target,cmd,target);
						}
						sup = this;
						w.clicked.connect( w, function(x){ eval(events[this.objectName]);
						}
		 );
			}
			}catch(err){
				print("error: {0} - {1}".format(err, w.objectName));
			}
	}

	if(cacheOn){ //Retrieve historic values from registry
		for( var w in this.dailog.widgets){
			w = this.widget(w);
			if(w.hasOwnProperty('value')){
					w.value = this.cache(DialogName + '_'+ w.objectName);
			}
			else if(w.hasOwnProperty('plainText')){
					w.plainText = this.cache(DialogName + '_'+ w.objectName);
			}
			else if(w.hasOwnProperty('html')){
					 w.html = this.cache(DialogName + '_'+ w.objectName);
			}
			else if(w.hasOwnProperty('text') && w.hasOwnProperty('maxLength')){
					 w.text = this.cache(DialogName + '_'+ w.objectName);
			}
			else if(w.hasOwnProperty('checked')){
				w.checked = this.cache(DialogName + '_'+ w.objectName);
			}
			else if(w.hasOwnProperty('currentIndex')){ //Combobox  //currentIndex is the index...
				w.currentIndex = w.items.indexOf(this.cache(DialogName + '_'+ w.objectName));
			}
		}

	}

	if (this.isFunction(beforeCallback)) {  //Check if we need to do the before callback
		beforeCallback.call(this);  //ypically this is to set default values for some/all widgets and also connect signels to slots in GUI (onclick events)
	}

	while(true){
		if (modal){ //Modal
			if(!this.dailog.exec()){
			  return false;  //user pressed cancel button so stop everything
			}
		}
		else{ //Modeless
			this.dailog.show();
			return true;
		}
	if (this.isFunction(afterCallback)) {
		if (afterCallback.call(this)){
		break; //all validation was successful
		}
	}
	else{
	  break; //finish looping without validation
	}
	}
	if(cacheOn){  //Store values in registry for next time
		for( var w in this.dailog.widgets){
			w = this.widget(w);
			if(w.hasOwnProperty('value')){
					 this.cache(DialogName + '_'+ w.objectName, w.value);
			}
			else if(w.hasOwnProperty('plainText')){
					 this.cache(DialogName + '_'+ w.objectName, w.plainText);
			}
			else if(w.hasOwnProperty('html')){
					 this.cache(DialogName + '_'+ w.objectName, w.html);
			}
			else if(w.hasOwnProperty('text') && w.hasOwnProperty('maxLength')){
					 this.cache(DialogName + '_'+ w.objectName, w.text);
			}
			else if(w.hasOwnProperty('checked')){
				this.cache(DialogName + '_'+ w.objectName, w.checked);
			}
			else if(w.hasOwnProperty('currentIndex')){ //Combobox  //currentIndex is the index...
				this.cache(DialogName + '_'+ w.objectName, w.currentText);
			}
		}
	}
	events = null;
	return true;
},
showDialog: function(name, validationCallback, defaultsCallback,cacheOn,modal){
	if(typeof modal == 'undefined') modal =true;
	if(typeof cacheOn == 'undefined') cacheOn =true;

	if(this.showAuto(name,
			cacheOn,
			function(){
				if(defaultsCallback != null) defaultsCallback.call(this);
			},
			function(){
				try{
					 if(validationCallback != null) {	validationCallback.call(this);}
					return true;
				}catch(error){
					MessageBox.warning('Input Warning: ' + error);
					return false;
				}
			 },
			 modal)) /* End of Show Dialog*/
	{
		var results = this.widgetResults();
		debug(results);

		return results;
	}
	else{
	throw "User pressed cancel button";
	}

},

showString : function(XMLString,beforeCallback, afterCallback)
{
	this.dailog = Application.loadUi(XMLString);
	if (this.isFunction(beforeCallback)) {  //Check if we need to do the before callback
		beforeCallback.call(this);  //typically this is to set default values for some/all widgets and also connect signels to slots in GUI (onclick events)
	}

	while(true){
	if(!this.dailog.exec()){
	  return false;  //user pressed cancel button so stop everything
	}
	if (this.isFunction(afterCallback)) {
		if (afterCallback.call(this)){
		return true; //all validation was successful
		}
	}
	else{
	  return true; //finish looping without validation
	}
	}
},


showFile : function(file){
//if (MNovaUtil.showFile("file")) {print("pressed OK")}
	this.dailog = Application.loadUiFile(file);
	return this.dailog.exec();
},


widget: function(name){
//MNovaUtil.widget('id').checked
	try{
	  return this.dailog.widgets[name];
	}
	catch (err){
	  return null;
	}
},

widgetResults: function(){
//$.widgetResults() returns JSON object {name: value, name: value}
	var result = {};
		for( var w in this.dailog.widgets){
			w = this.widget(w);
			if(w.objectName.indexOf('groupBox') == 0 || w.objectName.indexOf('Button') != -1 || w.objectName.length <= 1){
				//ignore this widget
			}
			else if(w.hasOwnProperty('value')){
				result[w.objectName] = w.value;
			}
			else if(w.hasOwnProperty('plainText')){
				result[w.objectName] = w.plainText;
			}
			else if(w.hasOwnProperty('html')){
				result[w.objectName] = w.html;
			}
			else if(w.hasOwnProperty('text') && w.hasOwnProperty('maxLength')){
				result[w.objectName] = w.text;
			}
			else if(w.hasOwnProperty('checked')){
				result[w.objectName] = w.checked;
			}
			else if(w.hasOwnProperty('currentText')){ //Combobox  //currentIndex is the index...
				result[w.objectName + "_Index"] = w.currentIndex;
				result[w.objectName] = w.currentText;
			}
		}
	return result;
},

widgetsInfo : function()
{
//MNovaUtil.widgetsInfo()
	print('-- Start Debug Info --');
	try{
	for( var w in this.dailog.widgets){
	  if(w.length > 0){
	print('-----------------');
	print('Widget Name: ' + w);

	try{
	  var item =this.dailog.widgets[w];
	  for( var prop in item){
		if(item.hasOwnProperty(prop) && typeof item[prop] != 'function'){
		print("        Property: " + prop +" = "+ item[prop] );
		}
	  }
	}catch (err) {print("Could not print all properties");}
	  }
	}
	}catch(err1) {print("could not find dialog in scope");}
	print('-- End Debug Info --');
},


clicked : function(source,target,callback){
//MNovaUtil.clicked('uPickButton','uReportDirectory',function(){ $.widget('uReportDirectory').text = $.pickFolder('NovartisSampleFolder');}/* SourceId, TargetId, Delegate*/ )
	this.widget(source).clicked.connect(
		this.widget(target),
		function(){ /*Event Handler Action => Slot */
			  callback.call(this);
		}
		 );
},

progressShow: function(title, min, max, buttonText){
	title = title || 'Script Progress';
	buttonText = buttonText || 'Stop';
	min = min || 0;
	max = max || 100;
	this.pd = new ProgressDialog();
	this.pd.labelText = title;
	this.pd.setCancelButtonText(buttonText);
	this.pd.minimumDuration=0;
	this.pd.maximum = max;
	this.pd.minimum = min;
	this.pd.value = min;
	this.pd.show();
},

progressHide: function(){
	if(this.hasOwnProperty('pd') && this.pd != null){
		this.pd.hide();
		this.pd = null;
		return;
	}
},

progressChanged: function(value, title){
		if(!this.hasOwnProperty('pd')) return;
		if (this.pd.wasCanceled){
			this.progressHide();
			throw 'Progress stopped by user';
		}
		this.pd.value = value;
		this.pd.labelText = title || this.pd.labelText;
		if (Math.ceil(this.pd.value) >= 100){
			this.progressHide();
			return;
		}
		this.pd.repaint()
		this.pd.setFocus();
		mainWindow.processEvents();
},

disposeDialog: function(){
//MNovaUtil.dispose() //free up RAM of dialog box
	if(this.dialog){
	 if(this.dialog.widgets){
	this.dailog.widgets.length = 0;
	this.dailog.widgets = null;
	  }
	  this.dailog = null;
	}

},

isFunction: function (obj) {
	/// <summary>Determine if the argument passed is a Javascript function object.
	/// </summary>
	/// <returns type="boolean" />
	/// <param name="obj" type="Object">Object to test whether or not it is a function.</param>

	return toString.call(obj) === "[object Function]";
},

validate: function (widgetName, invalid, errorMessage) {
   if(this.widget(widgetName).text == invalid){
	  //MessageBox.warning(errorMessage, MessageBox.Ok);
	  throw errorMessage; /*Repeat the dialog box, because invalid user input*/
   }
},

validFileExists: function (widgetName, errorMessage) {
	var fileTest = this.widget(widgetName).text;
	if(!File.exists(fileTest)) {
		throw  errorMessage;
	}
},

validDirExists: function (widgetName, errorMessage) {
	var path = this.widget(widgetName).text;
	var dir = new Dir(path);
	if (!dir.exists){
		throw errorMessage;
	}
},

validDirForSavingFile: function (widgetName, errorMessage) {
	var path = this.widget(widgetName).text;
	if(path.indexOf('\\') != -1){
		path = path.substring(0,path.lastIndexOf('\\'));
	}
	if(path.indexOf('/') != -1){
		path = path.substring(0,path.lastIndexOf('/'));
	}
	var dir = new Dir(path);
	if (!dir.exists){
		throw errorMessage;
	}
},

validateRegex: function (widgetName, validPattern, errorMessage) {
   if(!validPattern.test(this.widget(widgetName).text)){
	  throw errorMessage;
   }
},

validEmail: function(widgetName, errorMessage) {
  var validPattern =/^[A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,})$/i;
  this.validateRegex(widgetName, validPattern, errorMessage);
},

validNumeric: function(widgetName, errorMessage) {
  var validPattern =/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/;
  this.validateRegex(widgetName, validPattern, errorMessage);
},

validInteger: function(widgetName, errorMessage) {
  var validPattern =/(^-?\d\d*$)/;
  this.validateRegex(widgetName, validPattern, errorMessage);
},

validDate: function(widgetName, errorMessage) {
  var validPattern =/^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/;
  this.validateRegex(widgetName, validPattern, errorMessage);
},

validRange : function(widgetName, minValue, maxValue, errorMessage) {
   var x = parseInt(this.widget(widgetName).text);
   if (x < minValue || x > maxValue){
	  throw errorMessage; /*Repeat the dialog box, because invalid user input*/
   }
},

validLength : function(widgetName, length, errorMessage) {
   var x = this.widget(widgetName).text.length;
   if (x != length){
	  throw errorMessage; /*Repeat the dialog box, because invalid user input*/
   }
},

validMinMaxLength : function(widgetName, minLength, maxLength, errorMessage) {
   var x = this.widget(widgetName).text.length;
   if (x < minLength || x > maxLength){
	  throw errorMessage; /*Repeat the dialog box, because invalid user input*/
   }
},

validEmpty : function(widgetName, errorMessage) {
   var strTemp = this.widget(widgetName).text;
   if(strTemp.length > 0){
	 return;
   }
   throw errorMessage; /*Repeat the dialog box, because invalid user input*/
},


//-----------------------------------------File IO Extensions-------------------------------------------

fileExists : function(fileReference)
{

//If file exists show replace dialog box.  Returns true if want to save ...returns flase if do not replace.
	if(fileReference.exists)
	{
		if(this.show("FileExists")) true;
		else return false;
	}
	else return true;
},


//MNovaUtil.fileOpen(filename)
fileOpen : function(filename)
{
	serialization.fileHistory = false;
	if (!serialization.open(filename)){
			throw "Error opening and processing the file {0}.".format(filename);
	}
	serialization.fileHistory = true;
},
//MNovaUtil.fileclosefilename)
fileSave : function (filename,format, history, allowOverwrite) {
		this.saveFile(filename,format, history, allowOverwrite);
},
saveFile : function (filename,format, history, allowOverwrite) {
//MNovaUtil.saveFile("c:/sampleReport","pdf", true)
	  //	Check if file already exists and ask if user wants to overwrite
	  allowOverwrite = allowOverwrite || false;
		  serialization.fileHistory = history || false;
	  var f = new File(filename);
	  if(allowOverwrite || this.fileExists(f) )
	  {
		serialization.save(filename,format);
	  }
	  serialization.fileHistory = true;
 },


fileClose : function()
{
	serialization.fileHistory = false;
	this.find('DOC').close();
	serialization.fileHistory = true;
},

getFilename : function(path){
  try{
	var list;
	if(path.indexOf('/') != -1){
		list = path.split('/');
	}
	else{
	  list = path.split('\\');
	}
	for(var i=0;i< list.length;i++){
		if(list[i].indexOf('.raw') != -1 || list[i].indexOf('.RAW') != -1) return list[i];
	}
		return list[list.length - 1]; //return last item in path
	  }catch (err) {return list[list.length - 1]}
},

getMassRAWPath: function(msItem){
	if (!msItem.hasOwnProperty('datasetFileName')){
		return null;
	}
	var msPath = new Dir (msItem.datasetFileName);

	if(msPath.exists){
		return msPath.absPath;
	}
	else{
		msPath.cdUp();
		return msPath.absPath;
	}
},

getFilenameWithoutExtension : function(path){
try{
  var n = this.getFilename(path);
  return n.substring(0,n.length - 4);
 }catch(err) {return null;}
},

exportImage : function (filename, i) {
//MNovaUtil.savePage("c:/sampleReport","pdf", true)
	  //	Check if file already exists and ask if user wants to overwrite
			this.checkFunction("exportImage");
			var cur = this.window.curPage();
			this.window.setCurPageIndex(i);
		this.saveFile(filename,'png', false, true);
			this.window.setCurPage(cur);
 },

//Create a new Document and clone the current page to the new document
pageCopyToNewDocument : function(){
	//var data = $('P').cloneItems($.items());
	this.checkFunction("pageCopyToNewDocumen");
	var p = mainWindow.activeDocument.curPage();
	var dw = mainWindow.newDocument();
	dw.clonePages([p]); //needs to be array
	dw.deletePages([dw.page(0)]);

	mainWindow.setActiveWindow(dw);
	return dw;  //dw.close();
},

writeFile : function(fileName, text){

	if (!fileName.length)
		return;
	var fout = new File(fileName);
	fout.open(File.WriteOnly);
	var sout = new TextStream(fout);
	sout.codec="UTF-8"
	sout.write(text);
	fout.close();
},

appendFile : function(fileName, text){

	if (!fileName.length)
		return;
	var fout = new File(fileName);
	fout.open(File.ReadWrite);
	var sout = new TextStream(fout);
	sout.pos = fout.size;
	sout.write(text);
	fout.close();
},

readFile : function(fileName){
	if (!fileName.length)
		return;

	var fin = new File(fileName);

	fin.open(File.ReadOnly);
	var ts = new TextStream(fin);
	var str = ts.readAll();
	fin.close();
	return str;
},

readFile : function(fileName){
	if (!fileName.length)
		return;

	var fin = new File(fileName);

	fin.open(File.ReadOnly);
	var ts = new TextStream(fin);
	var str = ts.readAll();
	fin.close();
	return str;
},

readFileCSV: function(file){
		if(!File.exists(file)){
			return null;
		}
		var sampleList = this.readFile(file);
		var data = this.csvToArray(sampleList);
		return data;
},

// This will parse a delimited csv into an array ofarrays.
csvToArray: function( strData, strDelimiter ){
	// then default to comma.
	strDelimiter = (strDelimiter || ",");
	var arrData = [[]];
		var arrMatches = null;
	// Create a regular expression to parse the CSV values.
	var objPattern = new RegExp(
		(   "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" + 			// Delimiters.
			"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +                    	// Quoted fields.
			"([^\"\\" + strDelimiter + "\\r\\n]*))"             	// Standard fields.
		), "gi" );

	while (arrMatches = objPattern.exec( strData )){
		// Get the delimiter that was found.
		var strMatchedDelimiter = arrMatches[ 1 ];
		// Check to see if the given delimiter has a length
		// (is not the start of string) and if it matches
		// field delimiter. If id does not, then we know
		// that this delimiter is a row delimiter.
		if (strMatchedDelimiter.length && (strMatchedDelimiter != strDelimiter)){
			arrData.push( [] );
		}
		if (arrMatches[ 2 ]){
			// We found a quoted value unescape any double quotes.
			var strMatchedValue = arrMatches[ 2 ].replace(new RegExp( "\"\"", "g" ),"\"");
		} else {
			// We found a non-quoted value.
			var strMatchedValue = arrMatches[ 3 ];
		}
		arrData[ arrData.length - 1 ].push( strMatchedValue );
	}
	arrData.pop();
	return( arrData );
	},




pickOpenFile : function(registryName,filter,title){
  var title = title || "Open File";
  filter = filter || '*.*';
  var settings = Settings();
  var folder = settings.value( registryName, Dir.home());
  folder = FileDialog.getOpenFileName(filter,folder, title);
  if (folder=="")
	  folder=this.dailog.widgets[registryName].displayText;
  settings.setValue(registryName, folder);
  return folder;
},

pickOpenFiles : function(registryName,filter,title){
 var title = title || "Open Files";
  filter = filter || '*.*';
  var settings = Settings();
  var folder = settings.value( registryName, Dir.home());
  folder = FileDialog.getOpenFileNames(filter,folder, title);
  if (folder=="")
	  folder=this.dailog.widgets[registryName].displayText;
  settings.setValue(registryName, folder);
  return folder;
},
pickSaveFile : function(registryName, filter,title){
  var title = title || "Save File";
  filter = filter || '*.*';
  var settings = Settings();
  var folder = settings.value( registryName, Dir.home());
  folder = FileDialog.getSaveFileName(filter,folder, title);
  if (folder=="")
	  folder=this.dailog.widgets[registryName].displayText;
  settings.setValue(registryName, folder);
  return folder;
},

pickFolder : function(registryName,title){
  title = title || "Pick a Folder";

  var settings = Settings();
  var folder = settings.value( registryName, Dir.home());
  folder = FileDialog.getExistingDirectory( folder, title);
  if (folder=="")
	  folder=this.dailog.widgets[registryName].displayText;
  settings.setValue(registryName, folder);
  return folder;
},

getFilesWithMask: function(baseDir,pathMask){
	var dir = new Dir(baseDir);
	return dir.entryListAdv(pathMask);
},

getFiles: function(baseDir){
	var dir = new Dir(baseDir);
	return dir.entryList("*", Dir.Files, Dir.Name) ;
},

cache : function(registryName,val){
  var settings = Settings();
  if(val == null){
	  return settings.value(registryName,"");
   }
   else{
	  settings.setValue(registryName, val);
   }
},

//-----------------------------------------Page & MNR Spectrum Reporting---------------------------------------------------
//MNovaUtil.text("Title",{top:5, left:30, height:20, width:100});
text : function (text, options) {
	text = text || "<No Text>" ;
	var item = draw.text(text, true);
	this.style(item,options);
	this.offset(item);
	return item;
},
//MNovaUtil.image(filename)
image : function(filename){
	this.loadLogo(filename);
},
//MNovaUtil.loadLogo(filename)
loadLogo : function(filename)
{
	serialization.fileHistory = false;
	serialization.open(filename);
	serialization.fileHistory = true;
	this.find("P").update();
},
//MNovaUtil.arrow({top:5, left:300, height:20, width:100});
arrow : function (options) {
	var item = draw.arrow( options.left, options.top, options.left + options.width, options.top + options.height, true, false);
	this.style(item,options);
	this.offset(item);
	return item;
},

//MNovaUtil.ellipse({top:5, left:300, height:20, width:100});
ellipse : function (options) {
	var item = draw.ellipse( options.width, options.height);

	this.style(item,options);
	this.offset(item);
	return item;
},

//MNovaUtil.rectangle({top:5, left:300, height:20, width:100});
rectangle : function (options) {
	var item = draw.rectangle( options.width, options.height);
	this.style(item,options);
	this.offset(item);
	return item;
},

//MNovaUtil.style({color:'red', lineColor:'blue', lineStyle: PageItem.DashLine, opacity:50});

style : function (item, options) {
//lineStyle: {PageItem.DashDotDotLine, PageItem.DashDotLine, PageItem.DashLine, PageItem.DotLine, PageItem.NoLine, PageItem.SolidLine}
	if (item == null) return null;

	for( prop in options){
	  try{
	  eval("item.{0} = options.{1};".format(prop,prop));
	  }catch (err) {
	  print("Error in Styling {0} with property: {1}".format(item, prop));
	  print("item.{0} = options.{1};".format(prop,prop));
	  }

	}

	return item;
},

//MNovaUtil.offset(item);  //Place on page
offset : function (item) {

	item.bottom += this.pageOffest.top;
	item.right += this.pageOffest.left;
	item.top += this.pageOffest.top;
	item.left += this.pageOffest.left;
},

//MNovaUtil.parseOptions({top:5, left:300, height:20, width:100});
parseOptions : function (options) {

	options = options || {}; //If not set correctly give options a default
	options.top = options.top || 0;
	options.left = options.left ||  0;

	options.top += this.pageOffest.top;
	options.left += this.pageOffest.left;

	return options;
},

//MNovaUtil.setPosition(item, options);
setPosition : function (item, options) {

	var width = item.width,
		height = item.height;

	options = this.parseOptions(options);

	if (item.top < options.top) {
			item.bottom = parseFloat(options.top + height, 10);
			item.top = options.top;

	} else {
		item.top = options.top;
		item.bottom = parseFloat(options.top + height, 10);
	}

	if (item.left < options.left)  {
		item.right = parseFloat(options.left + width, 10);
		item.left = options.left;

	} else {
		item.left = options.left;
		item.right = parseFloat(options.left + width, 10);
	}

	if(typeof options.width != 'undefined'){
	item.width = options.width;
	}
	if(typeof options.height != 'undefined'){
	item.height= options.height;
	}

},

//movePosition(item, {top: 5, left:50});
//movePosition (item, {xShift: 5, yShift:50});

movePosition : function (item, options) {

	var xShift, yShift;

	options.top = options.top || 0;
	options.left = options.left ||  0;

	if (options.xShift) {
		xShift = options.xShift;
	} else {
		xShift = -options.left;
	}
	if (options.yShift) {
		yShift = options.yShift;
	} else {
		yShift = options.top;
	}

	item.translate(xShift, yShift);
},



//MNovaUtil.alert("Failure text - stop script with exception");
alert : function (text) {
	MessageBox.critical(text, MessageBox.Ok);
	throw text;
},

//-------------------------------------------------String Extensions--------------------------------------------------
//"test string".wrap("h4");
wrap : function (format) {
	var str = this;
	return "<{0}>{1}</{0}>".format(format,str);
},

//"String pattern {0} with items {1} and {2}".format("Some Data",5, new Date());
format : function() {
	var formatted = this;
	for(var i= 0; i< arguments.length;i++) {
	formatted = formatted.replace("{" + i + "}", arguments[i]);
	}
	return formatted;
},

//"String pattern {0} with items {1} and {2}".print("Some Data",5, new Date());
print : function () {
	var formatted = this;
	for(var i= 0; i< arguments.length;i++) {
	formatted = formatted.replace("{" + i + "}", arguments[i]);
	}
	print(formatted);
},
font : function (number) {
	var str = this;
	return "<font face='arial' size='{0}'>{1}</font>".format(number,str);
},


nucleus: ["1H", "13C", "19F", "31P", "14N", "15N", "2H", "35Cl", "37Cl", "10B", "11B", "29Si", "6Li", "7Li", "27Al", "23Na", "17O", "107Ag", "109Ag", "129Xe", "207Pb", "63Cu", "65Cu", "3H", "3He", "25Mg", "39K", "43Ca", "57Fe", "59Co", "119Sn", "133Cs", "195Pt", "77Se", "89Y", "103Rh", "113Cd", "125Te", "183W", "187Os", "199Hg", "205Tl", "9Be", "21Ne", "33S", "45Sc", "47Ti", "61Ni", "49Ti", "51V", "53Cr", "55Mn", "67Zn", "71Ga", "73Ge", "75As", "81Br", "83Kr", "87Rb", "87Sr", "91Zr", "93Nb", "95Mo", "99Tc", "99Ru", "101Ru", "105Pd", "115In", "121Sb", "127I", "131Xe", "137Ba", "138La", "139La", "177Hf", "179Hf", "181Ta", "187Re", "189Os", "193Ir", "197Au", "201Hg", "209Bi"],
//---------------------------------------Find Items--------------------------------------------------
//used in ctor for parsing parameter:
// Search and return single item or array of items
//Can be used with .forEach() for iterating through arrays
/*
Example of using Array results:
//for each item in the Peak table of the active spectrum output the Peak intensity

$('S PK').forEach(function(item,$){
			print(item.intensity);
		 });

Return MainWindow
$.find()			Get the root Object - MNova Application (MainWindow)

Return Document(s)
$.find('DOC')   	Active document
$.find('DOCS') 		All documents

Return Pages - (current page or indexed)
$.find('P') 		get the current page
$.find('P', 0) 		get the 1st page
$.find('P', 1) 		get the 2nd page
$.find('P', 2) 		get the 3rd page

Return count of items - (current page or indexed)
$.find('? #')  or $.find('? #', 2)       Count All items      (current page and 3rd page)
$.find('S #')  or $.find('S #',0)        Count NMR spectrum   (current page or 1st page)
$.find('MS #') or $.find('MS #',0)       Count Mass spectrum  (current page or 1st page)
$.find('O #')  or $.find('O #',0)        Count OLE item       (current page or 1st page)
$.find('AR #') or $.find('AR #',0)       Count arrow item     (current page or 1st page)
$.find('IM #') or $.find('IM #',0)       Count Image item     (current page or 1st page)
$.find('EL #') or $.find('EL #',0)       Count ellipse item   (current page or 1st page)
$.find('PO #') or $.find('PO #',0)       Count Polygon item   (current page or 1st page)
$.find('RE #') or $.find('RE #',0)       Count rectangle item  (current page or 1st page)
$.find('TE #') or $.find('TE #',0)       Count text item      (current page or 1st page)

Return 1 active item from page - (current page or indexed)
$.find('A')  or $.find('A', 2)       Any active item (current page and 3rd page)
$.find('S')  or $.find('S', 2)       NMR spectrum    (current page and 3rd page)
$.find('MS') or $.find('MS', 2)      Mass item       (current page and 3rd page)
$.find('A')  or $.find('A', 2)       active item     (current page and 3rd page)
$.find('O')  or $.find('O', 2)       OLE item        (current page and 3rd page)
$.find('AR') or $.find('AR', 2)      Arrow item      (current page and 3rd page)
$.find('IM') or $.find('IM', 2)      Image item      (current page and 3rd page)
$.find('EL') or $.find('EL', 2)      Ellipse item    (current page and 3rd page)
$.find('PO') or $.find('PO', 2)      Polygon item    (current page and 3rd page)
$.find('RE') or $.find('RE', 2)      Rectangle item   (current page and 3rd page)
$.find('TE') or $.find('TE', 2)      Text item       (current page and 3rd page)

Return 1 indexed item from page - (current or selected page)
$.find('S 1')  or $.find('S 1',0)        Get 2nd NMR spectrum (current page or 1st page)
$.find('MS 2') or $.find('MS 2',0)       Get 3rd Mass spectrum (current page or 1st page)
$.find('O 2')  or $.find('O 2',0)        Get 3rd OLE item (current page or 1st page)
$.find('AR 0') or $.find('AR 0',0)       Get 1st arrow item (current page or 1st page)
$.find('IM 3') or $.find('IM 3',0)       Get 4th Image item (current page or 1st page)
$.find('EL 9') or $.find('EL 9',0)       Get 10th ellipse item (current page or 1st page)
$.find('PO 2') or $.find('PO 2',0)       Get 3rd Polygon item (current page or 1st page)
$.find('RE 2') or $.find('RE 2',0)       Get 3rd rectangle item (current page or 1st page)
$.find('TE 2') or $.find('TE 2',0)       Get 3rd text item (current page or 1st page)

Returns Array for table items related to the active spectrum - (cannot use page numbers as it is only for the current page)
$.find('S M')     Get Multiplets table for active NMR Spectrum
$.find('S PK')    Get Peak table for active NMR Spectrum
$.find('S GM')    Get GSD Multiplets table for active NMR Spectrum
$.find('S GP')    Get GSD peak table for active NMR Spectrum
$.find('S IN')    Get Integrals table for active NMR Spectrum

Returns Array of table items related to indexed spectrum - (current or selected page)
$.find('S 0 M')  or $.find('S 0 M',1)       Get Multiplet table for 1st NMR Spectrum       (current page or 2nd page)
$.find('S 1 PK') or $.find('S 1 PK',0)      Get Peaks table for 2nd NMR Spectrum           (current page or 1st page)
$.find('S 2 GM') or $.find('S 2 GM',6)      Get GSD Multiplets table for 3rd NMR Spectrum  (current page or 7th page)
$.find('S 1 GP') or $.find('S 1 GP',3)      Get GSD Peaks table for 2nd NMR Spectrum       (current page or 4th page)
$.find('S 0 IN') or $.find('S 0 IN',2)      Get Integrals for 1st NMR Spectrum             (current page or 3rd page)

Returns Array of items form ALL pages
$.find('* P')           array of all page
$.find('* S')           array of all NMR spectrum on all pages

Returns Array of items form SELECTED pages
$.find('@ P')          array of selected pages
$.find('@ A')          array of all selected items on page
$.find('@ S')          array of NMR objects from currently selected pages (if empty array of active NMR)

*********** TO IMPLEMENT ********************
Stacked NMR Spectrum - Returns a inner spectrum inside a stacked spectrum - (current or selected page)
$.find('S 0>0')  or $.find('S 0>0',1)           Get 1st stacked NMR spectrum inside the first Spectrum Stack (current page or 2nd page)
$.find('S 0>1')  or $.find('S 0>1',0)           Get 2nd stacked NMR spectrum inside the first Spectrum Stack (current page or 1st page)
$.find('S 0>2')  or $.find('S 0>2',1)           Get 3rd stacked NMR spectrum inside the first Spectrum Stack (current page or 2nd page)
$.find('S 1>0')  or $.find('S 1>0',5)           Get 1st stacked NMR spectrum inside the second Spectrum Stack (current page or 6th page)
$.find('S 1>1')  or $.find('S 1>1',5)           Get 2nd stacked NMR spectrum inside the second Spectrum Stack (current page or 6th page)
$.find('S 1>2')  or $.find('S 1>2',5)           Get 3rd stacked NMR spectrum inside the second Spectrum Stack (current page or 6th page)

Stacked NMR Spectrum - Returns Array of table items related to indexed spectrum - (current or selected page)
$.find('S 0>0 M')  or $.find('S 0>0 M',1)       Get Multiplet table for 1st child stacked spectrum inside 1st Spectrum           (current page or 2nd page)
$.find('S 0>1 PK') or $.find('S 0>1 PK',0)      Get Peaks table  for 2nd child stacked spectrum inside 1st NMR Spectrum          (current page or 1st page)
$.find('S 0>2 GM') or $.find('S 0>2 GM',6)      Get GSD Multiplets table for 3rd child stacked spectrum inside 1st NMR Spectrum  (current page or 7th page)
$.find('S 0>3 GP') or $.find('S 0>3 GP',3)      Get GSD Peaks table for 4th child stacked spectrum inside 1st NMR Spectrum       (current page or 4th page)
$.find('S 0>4 IN') or $.find('S 0>4 IN',2)      Get Integrals for 5th child stacked spectrum inside 1st Spectrum             (current page or 3rd page)

*/

find : function(selector, page)
{

	  this.checkFunction("find");
	  this.found = '';
		try{
		  var dw = new DocumentWindow(mainWindow.activeWindow());

		  if(parseInt(page) >= 0){
			mainWindow.activeDocument.setCurPageIndex(page)
		  }

		  this.page = mainWindow.activeDocument.curPage();
		}catch (err){
			return []; //what about null???
		}
	  if(selector === null){
		return mainWindow;
	  }

	  var MapType= {
	"MS": "Mass Spectrum",
	"M": "Molecule",
	"S": "NMR Spectrum",
	"O": "OLE Object",
	"AR": "Arrow",
	"IM": "Image",
	"EL": "Ellipse",
	"PO": "Polygon",
	"RE": "Rectangle",
	"TE": "Text"};

	  switch (selector)
	  {
		case 'DOC': //Active document
		return dw;
		case 'DOCS': //All documents
		return mainWindow.documents();
	case 'A': //active item;
		try{
			return dw.getActiveItem();
		}catch (err){
			return null;
		}
	case 'P': //current page
		return dw.curPage();
	case 'Pages': //all page
	case '* P': //all page
		return dw.pages();
	case 'SelPages':
	case '@ P':
		 return dw.selectedPages();
	case 'SelItems':
	case '@ A':
		return dw.selection();
	case 'SelectedNMR':
	case '@ S':
		var selPages = dw.selectedPages();
				if (selPages.length ==0){ selPages = [this.page];}
		var found = [];
		for(var i=0;i< selPages.length;i++){
			try{
			for(var j=0;j< selPages[i].itemCount("NMR Spectrum");j++){
			  found.push( new NMRSpectrum(selPages[i].item(j,"NMR Spectrum")));
			}
			}catch (err) {}
		}
		//if (found.length ==0){
		//    return [ this.find('S') ];
		// }else{
		  return found;
		//}
		break;
	case '* S':
		var selPages = dw.pages();
				if (selPages.length ==0){ selPages = [this.page];}
		var found = [];
		for(var i=0;i< selPages.length;i++){
			try{
			for(var j=0;j< selPages[i].itemCount("NMR Spectrum");j++){
			  found.push( new NMRSpectrum(selPages[i].item(j,"NMR Spectrum")));
			}
			}catch (err) {}
		}
		return found;
		break;
	case 'S': //current specturm;
	case 'MS': //active Mass spectrum item;
		try{
			if(this.window.itemCount(MapType[selector]) > 0){
			return this.window.getActiveItem(MapType[selector]);
			//var str = "this.found = new {0}(this.window.getActiveItem(MapType[selector]));".format(type.replace(' ',''));
			//print(str);
			//eval(str);
			}
			else{
			return null;
			}
		}catch(err){
			print('No current item');
			return null;
		}
		case 'IM': //active Image item;
	case 'O':  //active OLE item;
	case 'AR': //active arrow item;
	case 'EL': //active ellipseitem;
	case 'PO': //active Polygon item;
	case 'RE': //active rectange item;
	case 'TE': //active text item;
		try{
		  var type = MapType[selector];
		  if (page.itemCount(type) > 0)
		  {
					  var res;
			  var str = "res = new {0}(this.window.getActiveItem(type));".format(type.replace(' ',''));
			  //print(str);
			  eval(str);
					  return res;
		  }
		  else{
			return null;
		  }
		}catch(err){
		  return null;
		}
	default:
				if(selector.indexOf('#') == 1){
					var uuid = selector.substring(1);
					return this.page.getItem(uuid);
				}
				//More complex selector
		var parts = selector.split(' ');
		if(parts.length >= 2){
			//$('M 2') or $('P 1') or $('S 0')
			if(parts[1] =='#'){
				switch (parts[0])
				{
				 case 'MS': return this.page.itemCount("Mass Spectrum");
				 case 'Mo': return this.page.itemCount("Molecule");
				 case 'S' : return this.page.itemCount("NMR Spectrum");
				 case 'AR': return this.page.itemCount("Arrow");
				 case 'IM': return this.page.itemCount("Image");
				 case 'EL': return this.page.itemCount("Ellipse");
				 case 'RE': return this.page.itemCount("Rectangle");
				 case 'TE': return this.page.itemCount("Text");
				 case 'O' : return this.page.itemCount("OLE Object");
				 case '?' : return this.page.itemCount();
				 }
			}
						if(parts[0] =='TE'){ //$.find('TE type:subtype]') or //$.find('TE type')
							var child = selector.substring(3).split(':');
				var _type = child[0];
							var _subtype = '';
							if(child.length >= 2){
								_subtype = child[1]; //strip off the [.....] from subtype
							}
							var found = [];
							for(var i = 0 ; i< this.page.itemCount("Text"); i++){
								var txtItem = this.page.item(i,'Text');
								if (txtItem.type == _type && txtItem.subtype.indexOf(_subtype) != -1){
									found.push(txtItem);
								}
							}
							return found;
			}
			else if(parts[0] != 'S' && parseInt(parts[1]).toString() !== 'NaN'){ //part[1] != NaN is an index value
				var idx = parseInt(parts[1]);
				switch (parts[0])
				{
				case 'P':  //$('P 1') second page
					  if(mainWindow.activeDocument.pageCount() > idx){
					  this.found = dw.page(idx);
					  }
					  else{
					  this.found = null;
					  }

					break;
				case 'IM': //Image item;
									if (this.page.itemCount('Image') > idx)
					{
										return this.page.item(idx, 'Image');
									}
								case 'S':  //specturm;
				case 'MS': //Mass spectrum item;
				case 'O':  //OLE item;
				case 'AR': //arrow item;
				case 'EL': //ellipse item;
				case 'PO': //Polygon item;
				case 'RE': //rectange item;
				case 'TE': //text item;
					var type = MapType[parts[0]];
					if (this.page.itemCount(type) > idx)
					{
										var res;
					var str = "res = new {0}(this.page.item(idx, type));".format(type.replace(' ',''));
					//print(str);
					eval(str);
					return res;
					}
					else{
					return null;
					}
					break;
				case 'M': //$('M 2') 3rd Mol Table
					return dw.getMolTableItem(idx);
					break;
				default:
				  this.found =[];

				}
				return this.found;
			}
			else if (parts[0] == 'S'){
							   if(this.nucleus.indexOf(parts[1]) != -1 && parts.length == 2){// $('S 1H') or $('S 13C') or $('S 19F') or ...
									var findNucleus = parts[1];
									var found = [];
									var specs = this.find('* S');
									if (specs.length > 0){
										this.find('* S').forEach(function(spec){
											 if(spec.getParam('Nucleus') === findNucleus){
												found.push(spec);
											 }
										});
									}
									return found;
							  }
							  else if (parseInt(parts[1]).toString() != 'NaN'){
									// $('S 0 M') or $('S 1 PK') or $('S 2 GM') or $('S 1 GP') or $('S 0 IN')
					var type = MapType[parts[0]];
					var idx = parseInt(parts[1]);
					if (this.page.itemCount(type) > idx){
					this.spec = new NMRSpectrum(this.page.item(idx, type));;
					}
					else {
					return [];
					}
				  }

				  else{
				// $('S M') or $('S PK') or $('S GM') or $('S GP') or $('S IN')
				  this.spec = new NMRSpectrum(nmr.activeSpectrum());
				  if(this.spec == null) return [];
				  parts[2] = parts[1];
				  }
				  try{
				  return this.specArrays(parts[2],this.spec);
				  }catch(err){
				  return [];
				  }
			}
		}
		break;
	  }
	  return this.found;
},


length : function(itemType){
	  this.checkFunction("length");
	  return this.page.itemCount(MapType[itemType]);
},
specArrays : function(selector, spec){
	  spec = spec || new NMRSpectrum(nmr.activeSpectrum());
	  switch (selector)
	  {
	case 'MT': //Multiplet table
		  return this.toArray(spec.multiplets());
		  break;
	case 'PK': //Peak Table
		  return this.toArray(spec.peaks());
		  break;
	case 'GM': //GSD Multiplets Array;
		  return this.toArray(spec.gsdMultiplets());
		  break;
	case 'GP': //GSD Peaks Array
		  return this.toArray(spec.gsdPeaks());
		  break;
	case 'IN': //integrals Array
		  return this.toArray(spec.integrals());
		  break;
	default:
		  return [];
	  }
},
toArray : function(list)
{ //Used by Peaks in $.find('S PK')

	   var count = list.count;
	   var itemArray = [];
	   for(i=0; i<count; i++)
	   {
			   itemArray[i] = list.at(i);
	   }
	   return itemArray;
},


//Internal use only
_each: function( object, callback, args ) {


		var name, i = 0,
			length = object.length,
			isObj = length === undefined || this.isFunction(object);

		if ( args ) {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.apply( object[ name ], args ) === false ) {
						break;
					}
				}
			} else {
				for ( ; i < length; ) {
					if ( callback.apply( object[ i++ ], args ) === false ) {
						break;
					}
				}
			}

		// A special, fast, case for the most common use of each
		} else {
			if ( isObj ) {
				for ( name in object ) {
					if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
						break;
					}
				}
			} else {
				for ( var value = object[0];
					i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
			}
		}

		return object;
	},


//----------------------------------------------------Dialogs UIs---------------------------------------------------------

defaultDialogs : function()
{
/// <summary>Read all Qt UIs into a object called diaogs array</summary>

	this.dialogs = new Array();
	this.dialogs['ChooseFormat'] = '<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0">  <class>Dialog</class>  <widget class="QDialog" name="Dialog">   <property name="geometry">    <rect>     <x>0</x>     <y>0</y>     <width>400</width>     <height>127</height>    </rect>   </property>   <property name="windowTitle">    <string>Choose Output Format</string>   </property>   <widget class="QGroupBox" name="groupBox">    <property name="geometry">     <rect>      <x>10</x>      <y>10</y>      <width>361</width>      <height>101</height>     </rect>    </property>    <property name="title">     <string>Select</string>    </property>    <widget class="QComboBox" name="formatBox">     <property name="geometry">      <rect>       <x>110</x>       <y>30</y>       <width>69</width>       <height>22</height>      </rect>     </property>     <property name="toolTip">      <string extracomment="Press OK to send Spectrum for registration in Data Management"/>     </property>     <item>      <property name="text">       <string>MNOVA</string>      </property>     </item>     <item>      <property name="text">       <string>PDF</string>      </property>     </item>    </widget>    <widget class="QLabel" name="label_2">     <property name="geometry">      <rect>       <x>20</x>       <y>30</y>       <width>81</width>       <height>16</height>      </rect>     </property>     <property name="text">      <string>Output Format</string>     </property>    </widget>    <widget class="QDialogButtonBox" name="buttonBox">     <property name="geometry">      <rect>       <x>10</x>       <y>60</y>       <width>341</width>       <height>32</height>      </rect>     </property>     <property name="orientation">      <enum>Qt::Horizontal</enum>     </property>     <property name="standardButtons">      <set>QDialogButtonBox::Ok</set>     </property>    </widget>   </widget>  </widget>  <resources/>  <connections>   <connection>    <sender>buttonBox</sender>    <signal>accepted()</signal>    <receiver>Dialog</receiver>    <slot>accept()</slot>    <hints>     <hint type="sourcelabel">      <x>248</x>      <y>254</y>     </hint>     <hint type="destinationlabel">      <x>157</x>      <y>274</y>     </hint>    </hints>   </connection>   <connection>    <sender>buttonBox</sender>    <signal>rejected()</signal>    <receiver>Dialog</receiver>    <slot>reject()</slot>    <hints>     <hint type="sourcelabel">      <x>316</x>      <y>260</y>     </hint>     <hint type="destinationlabel">      <x>286</x>      <y>274</y>     </hint>    </hints>   </connection>  </connections> </ui> ';
	this.dialogs['FileExists'] = '<?xml version="1.0" encoding="UTF-8"?><ui version="4.0"> <class>Dialog</class> <widget class="QDialog" name="Dialog">  <property name="geometry">   <rect>    <x>0</x>    <y>0</y>    <width>370</width>    <height>131</height>   </rect>  </property>  <property name="windowTitle">   <string>File Already Exists</string>  </property>  <property name="modal">   <bool>true</bool>  </property>  <layout class="QVBoxLayout" name="verticalLayout">   <item>    <widget class="QGroupBox" name="groupBox">     <property name="title">      <string/>     </property>     <layout class="QGridLayout" name="gridLayout">      <item row="0" column="0">       <widget class="QLabel" name="label_2">        <property name="text">         <string>Do you want to replace the existing file with this one?</string>        </property>       </widget>      </item>     </layout>    </widget>   </item>   <item>    <widget class="QDialogButtonBox" name="buttonBox">     <property name="orientation">      <enum>Qt::Horizontal</enum>     </property>     <property name="standardButtons">      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>     </property>    </widget>   </item>  </layout> </widget> <resources/> <connections>  <connection>   <sender>buttonBox</sender>   <signal>accepted()</signal>   <receiver>Dialog</receiver>   <slot>accept()</slot>   <hints>    <hint type="sourcelabel">     <x>248</x>     <y>254</y>    </hint>    <hint type="destinationlabel">     <x>157</x>     <y>274</y>    </hint>   </hints>  </connection>  <connection>   <sender>buttonBox</sender>   <signal>rejected()</signal>   <receiver>Dialog</receiver>   <slot>reject()</slot>   <hints>    <hint type="sourcelabel">     <x>316</x>     <y>260</y>    </hint>    <hint type="destinationlabel">     <x>286</x>     <y>274</y>    </hint>   </hints>  </connection> </connections></ui>';
}

}


//---------------------------------------global event handlers----------------------------------------
function connectButton($,textID, buttonID, fileFilter){
	/*Step 1: Set Default Values*/
	$.widget(textID).text = $.cache(textID);
	/*Step 2: Add event handlers to connect click events to widgets*/
	$.clicked(buttonID,textID,
			  function(){
				 if (textID.indexOf('DirText') != -1){
					$.widget(textID).text =  $.pickFolder(textID);
				 }
				 else if (textID.indexOf('SaveFileText') != -1){
					$.widget(textID).text =  $.pickSaveFile(textID,fileFilter);
				 }
				 else if (textID.indexOf('OpenFileText') != -1){
					$.widget(textID).text =  $.pickOpenFile(textID,fileFilter);
				 }
				 else if (textID.indexOf('OpenFilesText') != -1){
					$.widget(textID).text =  $.pickOpenFiles(textID,fileFilter);
				 }
			  });
	return true;
}
function debug(options,prefix) {
	prefix = prefix || '';
	var str = (typeof options);
	print('Start: {0}'.format(str));
	for( prop in options){
	  try{
	  print("{0} {1}: {2}\t\t({3})".format(prefix,prop,options[prop], typeof options[prop]));
		  if (typeof options[prop] == 'Object'){
			debug(options[prop], '\t');
		  }
	  }catch (err) {}
	}
	print('End: {0}'.format(str));
}

/* Array.prototype.paramFilter = function(paramName,paramValue){
		var found = [];
		specs.forEach(function(spec){
			 if(spec.getParam(paramName) === paramValue){
				found.push(spec);
			 }
		});
		return found;
} */
Array.prototype.each = function(callback, args ) {
			return MNovaUtil2.prototype._each( this, callback, args );

}
Array.prototype.each = function(callback, args ) {
			return MNovaUtil2.prototype._each( this, callback, args );

}

Date.prototype.formatMMDDYYYY = function(){
	return this.getMonth() +
	"/" +  this.getDate() +
	"/" +  this.getFullYear();
}
